package main

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"path"
	"strconv"
	"strings"

	"github.com/grafov/m3u8"
	requests "github.com/imroc/req"
	"github.com/mr-tron/base58"
)

type M3U8 struct {
	w        http.ResponseWriter
	r        *http.Request
	crc      string
	basePath string
	target   string
	baseDir  string
}

func NewM3U8Handle(w http.ResponseWriter, r *http.Request, target string) *M3U8 {
	path, err := os.Getwd()
	if err != nil {
		log.Println(err)
		return nil
	}
	return &M3U8{
		w:        w,
		r:        r,
		basePath: path,
		target:   target,
		baseDir:  "",
	}
}
func (server *M3U8) crcxnxx() string {
	u, err := url.Parse(server.target)
	var chkpath string
	if err == nil {
		chkpath = u.Path
		_all := strings.Split(chkpath, "/")
		chkpath = strings.Join(_all[2:], "/")
		server.crc = GetCRC32(chkpath)
		return server.crc
	}
	server.PanicError(errors.New("url parse error"))
	return ""
}
func (server *M3U8) Handle() {
	crc32 := server.crcxnxx()
	fmt.Println(crc32)
	var buf []byte
	var err error
	// if buf, err = DATABASE.Get([]byte(crc32)); err != nil {
	_r, err := requests.Get(server.target)
	server.PanicError(err)
	baseDir, _ := path.Split(server.target)
	server.baseDir = baseDir
	resp := _r.Response()
	defer func() {
		resp.Body.Close()
	}()
	if resp.StatusCode <= 210 && resp.StatusCode >= 200 {
		buf, err = ioutil.ReadAll(resp.Body)
		server.PanicError(err)
		// DATABASE.Put([]byte(crc32), buf)
	}
	// }
	entity, listType, err := m3u8.DecodeFrom(bytes.NewBuffer(buf), true)
	server.PanicError(err)

	var mediapl *m3u8.MediaPlaylist
	var masterpl *m3u8.MasterPlaylist
	switch listType {
	case m3u8.MEDIA:
		mediapl = entity.(*m3u8.MediaPlaylist)
		// fmt.Printf("%+v\n", mediapl)
		server.Replace(mediapl)
		mediapl.ResetCache()
		_b := mediapl.Encode().Bytes()
		server.w.Header().Set("Accept-Ranges", "bytes")
		server.w.Header().Set("Content-Type", "application/vnd.apple.mpegurl")
		// server.w.Header().Set("Access-Control-Allow-Credentials", "true")
		// server.w.Header().Set("Access-Control-Allow-Origin", "*")
		server.w.Header().Set("Cache-Control", "no-cache")
		server.w.Header().Set("Connection", "Keep-Alive")
		server.w.Header().Set("Content-Length", strconv.Itoa(len(_b)))
		server.w.Header().Set("Content-Range", fmt.Sprintf("bytes 0-%d/%d", len(_b)-1, len(_b)))
		server.w.Header().Set("Server", "PMR/0.1")
		server.w.WriteHeader(http.StatusOK)
		server.w.Write(_b)
	case m3u8.MASTER:
		masterpl = entity.(*m3u8.MasterPlaylist)
		// fmt.Printf("%+v\n", masterpl)
		server.ReplaceMaster(masterpl)
		masterpl.ResetCache()
		_b := masterpl.Encode().Bytes()
		server.w.Header().Set("Accept-Ranges", "bytes")
		server.w.Header().Set("Content-Type", "application/vnd.apple.mpegurl")
		// server.w.Header().Set("Access-Control-Allow-Credentials", "true")
		// server.w.Header().Set("Access-Control-Allow-Origin", "*")
		server.w.Header().Set("Cache-Control", "no-cache")
		server.w.Header().Set("Connection", "Keep-Alive")
		server.w.Header().Set("Content-Length", strconv.Itoa(len(_b)))
		server.w.Header().Set("Content-Range", fmt.Sprintf("bytes 0-%d/%d", len(_b)-1, len(_b)))
		server.w.Header().Set("Server", "PMR/0.1")
		server.w.WriteHeader(http.StatusOK)
		server.w.Write(_b)
	}
	// if t == m3u8.MEDIA {
	// 	//Replace(entity.(*m3u8.MediaPlaylist))
	// 	b = entity.Encode().Bytes()
	// }
}

func (server *M3U8) Replace(l *m3u8.MediaPlaylist) {
	for _, seg := range l.Segments {
		if seg != nil {
			var base58Str string
			if seg.URI[:4] == "http" {

			} else if seg.URI[:1] == "/" {
				u, err := url.Parse(server.target)
				if err == nil {
					base58Str = base58.Encode([]byte(u.Scheme + "://" + u.Host + seg.URI))
					seg.URI = base58Str
				}
			} else {
				base58Str = base58.Encode([]byte(server.baseDir + seg.URI))
				seg.URI = "/" + base58Str
			}
		}
	}
}
func (server *M3U8) ReplaceMaster(l *m3u8.MasterPlaylist) {
	for i := len(l.Variants) - 1; i >= 0; i-- {
		seg := l.Variants[i]
		if seg != nil {
			if seg.VariantParams.Name == "720p" || seg.VariantParams.Name == "1080p" {
				// l.Remove()
				l.Variants = append(l.Variants[:i], l.Variants[i+1:]...)
			}
			var base58Str string
			if seg.URI[:4] == "http" {

			} else if seg.URI[:1] == "/" {
				u, err := url.Parse(server.target)
				if err == nil {
					base58Str = base58.Encode([]byte(u.Scheme + "://" + u.Host + seg.URI))
					seg.URI = base58Str
				}
			} else {
				base58Str = base58.Encode([]byte(server.baseDir + seg.URI))
				seg.URI = "/" + base58Str
			}
		}
	}
}

func (this *M3U8) PanicError(err error) {
	if err != nil {
		panic(err)
	}
}
func (this *M3U8) PrintError(err error) {
	if err != nil {
		fmt.Println(err)
	}
}
